import biz.MeiTuan;
import exception.DishException;
import exception.ServiceTimeException;

import java.io.IOException;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.*;

import static biz.MeiTuan.*;

/**
 * Description：吃货联盟订餐系统（美团系统）客户端
 * Copyright (c), 2024, lbs
 * This program is protected by copyright laws.
 * Date： 2024年09月26日
 *
 * @author 刘宝顺
 * @version : 1.0
 **/
public class MeiTuanClient {
    /**
     * @param args
     */
    public static void main(String[] args) {
        MeiTuanClient customer = new MeiTuanClient();
        try (
                Socket client = new Socket("127.0.0.1", 7777);
                Scanner reader = new Scanner(client.getInputStream());
                PrintWriter pw = new PrintWriter(client.getOutputStream(), true);
                Scanner scanner = new Scanner(System.in)
        ) {
            //显示欢迎信息
            customer.show_info(reader, "WELCOME_INFO", System.lineSeparator(), false);

            //显示服务员信息
            customer.show_info(reader, "PROVIDER_SERVICE_FOR_CUSTOMER", System.lineSeparator(), false);

            EXIT_FLG:
            while (true) {
                //显示菜单信息
                customer.show_info(reader, "END_OF_MENU", System.lineSeparator(), false);

                //获得顾客选择
                customer.show_info(reader, "CHOICE", "", false);
                String choice = scanner.nextLine();
                pw.println(choice);

                switch (choice) {
                    case "1":
                        // 显示菜品信息
                        customer.showDishInfo(reader, scanner);
                        break;
                    case "2":
                        // 订餐
                        customer.order(reader, pw, scanner);
                        break;
                    case "3":
                        // 查看订单
                        customer.listOrders(reader, scanner);
                        break;
                    case "4":
                        // 签收订单
                        customer.confirmOrder(reader, pw, scanner);
                        break;
                    case "5":
                        // 删除订单
                        customer.removeOrder(reader, pw, scanner);
                        break;
                    case "6":
                        // 点赞
                        customer.thumbsUp(reader, pw, scanner);
                        break;
                    case "7":
                        // 退出系统
                        String flg = customer.exitSystem(reader, pw, scanner);
                        if ("Y".equalsIgnoreCase(flg)) {
                            break EXIT_FLG;
                        }
                        break;
                    default:
                        customer.show_info(reader, "ERROR_CHOICE", System.lineSeparator(), false);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private String exitSystem(Scanner reader, PrintWriter pw, Scanner scanner) {
        show_info(reader, "EXIT_SYSTEM", "", false);
        String flg = null;
        while (true) {
            flg = scanner.nextLine();
            if (!("Y".equalsIgnoreCase(flg) || "N".equalsIgnoreCase(flg))) {
                System.out.print("您录入的是【" + flg + "】，请在【Y、N】中进行选择！您的录入是：");
                continue;
            }
            pw.println(flg);
            if ("Y".equalsIgnoreCase(flg)) {
                show_info(reader, "THANK_YOU_USING", System.lineSeparator(), false);
            }
            break;
        }

        return flg;
    }

    private void thumbsUp(Scanner reader, PrintWriter pw, Scanner scanner) {
        show_info(reader, "THUMBS_UP", System.lineSeparator(), false);
        show_info(reader, "END_OF_DISH", System.lineSeparator(), false);
        show_info(reader, "THUMBS_UP_NO", "", false);
        getCommonDishNo(pw, scanner);
        show_info(reader, "THUMBS_UP_SUCCESS", System.lineSeparator(), false);
        judgeReturn(scanner);
    }

    private void removeOrder(Scanner reader, PrintWriter pw, Scanner scanner) {
        show_info(reader, "REMOVE_ORDER", System.lineSeparator(), false);

        String legalOrderNumbers = show_info(reader, "GET_ALL_REMOVE_ORDER_NO", "", true);
        if ("".equals(legalOrderNumbers)) {
            System.out.println("目前，没有【已完成】的订单，不能进行删除操作！");
        } else {
            show_info(reader, "REMOVE_ORDER_NO", "", false);
            getWillOperateOrderNo(pw, scanner, legalOrderNumbers, "注意：只有状态是【已完成】的订单才能删除！");
            show_info(reader, "LOGIC_REMOVE_SUCCESS", System.lineSeparator(), false);
        }

        judgeReturn(scanner);
    }

    private void confirmOrder(Scanner reader, PrintWriter pw, Scanner scanner) {
        show_info(reader, "CONFIRM_ORDER", System.lineSeparator(), false);

        String legalOrderNumbers = show_info(reader, "ALL_NORMAL_ORDER_NOS", "", true);
        if ("".equals(legalOrderNumbers)) {
            System.out.println("目前，没有【已预订】的订单，不能进行【签收】操作！");
        } else {
            show_info(reader, "CONFIRM_ORDER_NO", "", false);
            getWillOperateOrderNo(pw, scanner, legalOrderNumbers, "注意：只有状态是【已预订】的订单才能签收！");
            show_info(reader, "CONFIRM_ORDER_OVER", System.lineSeparator(), false);
        }

        judgeReturn(scanner);
    }

    /**
     * 获得需要签收的订单编号
     *
     * @param pw                PrintWriter
     * @param scanner           Scanner
     * @param legalOrderNumbers String
     */
    private void getWillOperateOrderNo(PrintWriter pw, Scanner scanner, String legalOrderNumbers, String msg) {
        while (true) {
            String orderNo = scanner.nextLine();
            List<String> orders = Arrays.asList(legalOrderNumbers.split(","));
            if (!orders.contains(orderNo)) {
                System.out.println(msg);
                System.out.print("您录入的订单编号是【" + orderNo + "】，非法！请在范围" + orders + "内选择！您的录入是：");
                continue;
            }
            pw.println(orderNo);
            break;
        }
    }

    private void listOrders(Scanner reader, Scanner scanner) {
        show_info(reader, "LIST_ORDERS", System.lineSeparator(), false);

        judgeReturn(scanner);
    }

    private void order(Scanner reader, PrintWriter pw, Scanner scanner) {
        show_info(reader, "WILL_ORDER", System.lineSeparator(), false);

        //直接判断
        int realOrderSize = Integer.parseInt(show_info(reader, "NOW_ORDER_SIZE", "", true));
        if (realOrderSize == MAX_ORDER_NUMBER) {
            show_info(reader, "MAX_ORDER_NUMBER", System.lineSeparator(), false);
            return;
        }

        //显示菜品信息
        show_info(reader, "END_OF_DISH", System.lineSeparator(), false);

        //顾客名
        show_info(reader, "NAME", "", false);
        getCutomerLegalInfo(pw, scanner, "姓名");

        //菜品编号
        show_info(reader, "DISH_NO", "", false);
        getCommonDishNo(pw, scanner);

        //菜品份数
        show_info(reader, "DISH_NUMBERS", "", false);
        getDishNumber(pw, scanner);

        //获得合法的时间
        show_info(reader, "TIME", "", false);
        getCommonTime(pw, reader, scanner);

        //获得合法的送餐地址
        show_info(reader, "ADDRESS", "", false);
        getCutomerLegalInfo(pw, scanner, "送餐地址");

        show_info(reader, "ORDER_INFOS", System.lineSeparator(), false);

        judgeReturn(scanner);
    }


    /**
     * 获得菜品份数
     *
     * @param pw      PrintWriter
     * @param scanner Scanner
     */
    private void getDishNumber(PrintWriter pw, Scanner scanner) {
        while (true) {
            String number = scanner.nextLine();
            if (!number.matches("\\d+") || Integer.parseInt(number) == 0) {
                System.out.print("您录入的是【" + number + "】，非法！请重新输入份数：");
                continue;
            }
            pw.println(number);
            break;
        }

    }

    /**
     * 获得合法的菜单序号
     *
     * @param scanner
     */
    private void getCommonDishNo(PrintWriter pw, Scanner scanner) {
        while (true) {
            try {
                getLegalDishNo(pw, scanner);
                break;
            } catch (DishException e) {
                System.out.print(e.getMessage());
            }
        }
    }


    /**
     * 获得合法的菜单序号
     *
     * @param pw
     * @param scanner
     * @return
     */
    private void getLegalDishNo(PrintWriter pw, Scanner scanner) {
        while (true) {
            String dishNoStr = null;
            try {
                dishNoStr = scanner.nextLine();
                int dishNo = Integer.parseInt(dishNoStr);
                //能执行下述的代码，证明录入的是合法的数字，但是，不一定是与业务吻合的菜单序号
                if (!judgeExist(dishNo)) {
                    //抛出的是与业务相关的异常
                    throw new DishException("您录入的菜单序号是【" + dishNo + "】，非法，请在范围" + MeiTuan.COMMON_DISH_NUMBERS + "之内重新录入！您的录入是：");
                } else {
                    pw.println(dishNo);
                    break;
                }
            } catch (InputMismatchException | NumberFormatException e) {//捕获的语法的异常
                System.out.print("您录入的菜单序号是【" + dishNoStr + "】，非法，请录入数字！您的录入是：");
            }
        }
    }

    /**
     * 判断顾客提供的菜单序号在不在本餐厅可选的菜单范围之内
     *
     * @param dishNo 顾客提供的菜单序号
     * @return true：在范围之内，false：不在范围之内
     */
    private boolean judgeExist(int dishNo) {
        return MeiTuan.COMMON_DISH_NUMBERS.contains(dishNo);
    }

    /**
     * 获得顾客合法的信息
     *
     * @param pw      PrintWriter
     * @param scanner Scanner
     * @param flg     标志
     */
    private void getCutomerLegalInfo(PrintWriter pw, Scanner scanner, String flg) {
        while (true) {
            String info = scanner.nextLine();
            if (!info.matches(MeiTuan.NORMAL_REGEX_INFO)) {
                System.out.print(flg.concat("不能是【" + info + "】，要求是汉字或是英数字！请重新输入："));
                continue;
            }
            pw.println(info);
            break;
        }
    }

    /**
     * 获得合法的送餐时间
     *
     * @param pw      网络字符输出流
     * @param reader  网络字符输入流
     * @param scanner 客户端控制台到内存的输入流
     * @throws ServiceTimeException 抛出服务时间异常
     */
    private void getIegalTime(PrintWriter pw, Scanner reader, Scanner scanner) throws ServiceTimeException {
        while (true) {
            String time = null;
            try {
                time = scanner.nextLine();
                int tmpTime = Integer.parseInt(time);

                //业务级别的异常
                if (tmpTime < BEGIN_TIME || tmpTime > END_TIME) {
                    throw new ServiceTimeException("您录入的送餐时间是【" + tmpTime + "】，非法，请在范围【" + BEGIN_TIME + "~" + END_TIME + "】之内选择！您的录入是：");
                }
                //能够执行到下述的语句，证明tmpTime取值完全合法（语法ok,业务ok）
                pw.println(time);
                return;
            } catch (NumberFormatException e) {//语法级别的错误
                System.out.print("您录入的送餐时间是【" + time + "】，非法，请在范围【" + BEGIN_TIME + "~" + END_TIME + "】之内选择！您的录入是：");
            }
        }
    }

    /**
     * 获得合法的送餐时间（语法，业务上都合法）
     *
     * @param pw     网络字符输出流
     * @param reader 网络字符输入流
     * @param input  客户端控制台到内存的输入流
     */
    private void getCommonTime(PrintWriter pw, Scanner reader, Scanner input) {
        while (true) {
            try {
                getIegalTime(pw, reader, input);
                return;
            } catch (ServiceTimeException e) {
                System.out.print(e.getMessage());
            }
        }
    }

    private void showDishInfo(Scanner reader, Scanner scanner) {
        show_info(reader, "END_OF_DISH", System.lineSeparator(), false);
        judgeReturn(scanner);
    }

    private String show_info(Scanner reader, String flg, String newLine, boolean isNeedReturnValue) {
        String line;
        List<String> content = new LinkedList<>();
        while (!flg.equals(line = reader.nextLine())) {
            if ("".equals(newLine)) {
                content.add(line);
            }
            if (!isNeedReturnValue) {
                System.out.print(line.concat(newLine));
            }

        }
        return content.size() > 0 ? content.get(0) : null;
    }

    /**
     * 输入0返回
     *
     * @param input
     */
    private void judgeReturn(Scanner input) {
        //让程序显得没那么突兀，需要接受录入
        System.out.print("\n输入0返回：");
        while (true) {
            String returnFlg = input.nextLine();
            if ("0".equals(returnFlg)) {
                break;
            }
            System.out.print("\n您录入的是【" + returnFlg + "】，不是0，请重新录入：");
        }
    }
}
